#include"ThreadPool.h"
#include "unistd.h"

ThreadPool::ThreadPool(size_t threadNum,size_t queSize)
:_threadNum(threadNum)
,_queSize(queSize)
,_threads()
,_taskQue(_queSize)
,_isExit(false)
{
    _threads.reserve(threadNum);
}

ThreadPool::~ThreadPool(){}

void ThreadPool::start(){
    //创建线程,加入vector(线程池)
    for(int i=0;i<static_cast<int>(_threadNum);++i){
        _threads.push_back(thread(&ThreadPool::doTask,this));
    }
    
}

void ThreadPool::stop(){
    
    //任务如果执行不完，就不能让子线程退出
    while(!_taskQue.empty()){
        sleep(1);
    }

    _isExit = true;

    //在回收之前将所有的工作线程唤醒
    _taskQue.wakeup();

    //将工作线程停止
    for(auto & th: _threads){
        th.join();
    }
}

void ThreadPool::addTask(ElemType&& ptask){
        _taskQue.push(ptask);
}

ElemType ThreadPool::getTask(){
    return _taskQue.pop();
}

//两个问题:
//1.线程池中的任务执行不完：任务队列中还有任务,
//stop函数的_isExit就设置为true,之后工作线程停止了
//解决方法：当任务队列中没有任务之后，再将_isExit设为true。
//
//2.线程池无法退出：在doTask中_isExit还没有被设置为Ture之前进入了while循环，
//进入之后才发现任务队列中没有任务，在getTask函数调用的pop函数中陷入阻塞，
//该子线程就一直处于睡眠状态，子线程无法结束，那么主线程也无法退出。
//解决方法：在结束之前唤醒所有线程,同时在pop函数中用flag标志位来标识是普通唤醒还是退出之前的全员唤醒。
void ThreadPool::doTask(){

    //用的是线程池是否退出的标志位？？？
    //子线程(工作线程)在获取全部任务之后,那么任务队列就是空,接下来子线程
    //会执行任务,也就是执行process函数，而主线程会执行stop函数的将标志位
    //_isExit设置为true的操作。如果子线程执行process的速率非常慢，那么当
    //子线程执行完任务之前主线程就将标志位设置为true,那么子线程就不会进入
    //到while循环中，那么成语就可以正常结束;如果process执行的非常快,但是
    //主线程还没有将标志位设置为true,那么子线程执行完process之后,有进入了
    //while循环中，在执行getTask的时候，也就是会执行TaskQueue中的pop,让后
    //陷入睡眠。
    while(!_isExit){
         ElemType cbtask = getTask();
         if(cbtask){
             cbtask();
         }else{
             /* cout << "ptask == nullptr" << endl; */
         }
    }
}
